package com.freesky.biz.citic.service;

import cn.hutool.core.date.DateUtil;
import cn.hutool.http.Header;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import com.freesky.biz.citic.config.CiticSmConfiguration;
import com.freesky.biz.citic.utils.TransProcessUtils;
import com.freesky.common.core.domain.AjaxResult;
import com.freesky.common.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

/**
 * 中信API文档V3版本
 */
@Service
public class CiticSendService {
    private static final Logger logger = LoggerFactory.getLogger(CiticSendService.class);

    @Autowired
    private CiticSmConfiguration smConfiguration;

    //正式环境
    private final String PREFIX_URL = "https://ifop.citicbank.com:30001";

    //正式环境商户号
    private final String MERNO = "340010010000044";

    public static String createNonceStr(){
        String sl = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        StringBuilder sb = new StringBuilder();
        for(int i = 0 ; i < 16 ; i ++){
            sb.append(sl.charAt(new Random().nextInt(sl.length())));
        }
        return sb.toString();
    }

    /**
     * 参考接口文档：http://sitopen.test.citicbank.com:10003/docs/#/guide/access/api/interface-api-v3
     * @param uri
     * @param busiData
     * @return
     */
    public AjaxResult sendRequest(String uri, String busiData){
        try{
            String algorithm = "sm-cert";
            String timestamp = DateUtil.format(new Date(),"yyyyMMddHHmmssSSS");
            String nonceStr = createNonceStr();

            StringBuilder signSource = new StringBuilder();
            signSource.append("POST");
            signSource.append("|");
            signSource.append(uri);
            signSource.append("|");
            signSource.append("CITICBANK-Algorithm=");
            signSource.append(algorithm);
            signSource.append(";");
            signSource.append("CITICBANK-AppID=");
            signSource.append(smConfiguration.getAppId());
            signSource.append(";");
            signSource.append("CITICBANK-CertGroupNo=");
            signSource.append(smConfiguration.getCertGroupNo());
            signSource.append(";");
            signSource.append("CITICBANK-Nonce=");
            signSource.append(nonceStr);
            signSource.append(";");
            signSource.append("CITICBANK-Timestamp=");
            signSource.append(timestamp);
            signSource.append("|");
            signSource.append(busiData);

            String headSign = URLEncoder.encode(TransProcessUtils.signBusiness(signSource.toString(),
                    smConfiguration.getPrivateReqKey()), "UTF-8");

            /*请求报文加密处理*/
            logger.info("getPubGatewayKey:"+smConfiguration.getPublicReqKey());
            String encryptData = URLEncoder.encode(TransProcessUtils.encryptBusiness(busiData, smConfiguration.getPublicReqKey()), "UTF-8");
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("encryptedMessage", encryptData);

            logger.info("encrypt:"+PREFIX_URL + uri +","+ jsonObject.toJSONString());


//            CITICBANK-Timestamp 请求时间戳yyyyMMddHHmmssSSS
//            CITICBANK-CertGroupNo 证书组编号
//            CITICBANK-Nonce 随机数32位，全局唯一
//            CITICBANK-Sign 签名结果;
            HttpResponse httpResponse = HttpRequest.post(PREFIX_URL + uri)
                    .header(Header.USER_AGENT, "Chrome")
                    .header("CITICBANK-Channel", "xcgw")
                    .header("CITICBANK-AppID", smConfiguration.getAppId())
                    .header("CITICBANK-Algorithm", algorithm)
                    .header("CITICBANK-Timestamp", timestamp)
                    .header("CITICBANK-CertGroupNo", smConfiguration.getCertGroupNo())
                    .header("CITICBANK-Nonce", nonceStr)
                    .header("CITICBANK-Sign", headSign)
                    .header(Header.CONTENT_TYPE,"application/json;charset=UTF-8")
                    .charset("utf8")
                    .body(jsonObject.toJSONString())
                    .timeout(5000)
                    .execute();

            /*获取响应状态码，2XX网关处理成功，4XX客户端错误 5XX服务端错误*/
            int statusCode = httpResponse.getStatus();

            String resopnseStr = httpResponse.body();
            if(StringUtils.isNotEmpty(resopnseStr)){
                resopnseStr = URLDecoder.decode(resopnseStr,"UTF-8");
            }
            logger.info("resp:"+resopnseStr);

            //Http状态码
            int status = httpResponse.getStatus();

            JSONObject responseJson = JSONObject.parseObject(resopnseStr);
            //网关响应码
            String gwCode = responseJson.getString("code");
            //网关响应描述
            String gwMsg = responseJson.getString("message");

            //业务响应加密报文
            String encryptBusiData = responseJson.containsKey("encryptedMessage") ? responseJson.getString("encryptedMessage") : null;
            String retBusiData = "";
            if (encryptBusiData != null && encryptBusiData.length() > 0) {
                retBusiData = TransProcessUtils.decryptBusiness(encryptBusiData, smConfiguration.getPrivateRespKey());
            }
            logger.info("retBusiData:"+retBusiData);

            httpResponse.close();

            if(statusCode<300&&statusCode>=200&&"AAAAAAA".equals(gwCode)){
                //todo 仅当满足改条件时，开放银行网关处理成功，但并不代表业务成功，
                // 具体业务处理结果，请对retBusiData解析后根据接口文档的描述进行业务后续处理
                // process(retBusiData)
                return AjaxResult.success("",retBusiData);
            } else {
                return AjaxResult.error(gwMsg);
            }

        } catch (Exception ioe){
            ioe.printStackTrace();
            logger.error(ioe.getMessage());
            return AjaxResult.error("操作失败!");
        }
//        System.out.println(JSON.toJSONString(result));
//        return result;
    }

    //支付请求
    //{"RETMSG":"授权码申请成功","RETCODE":"AAAAAAA","CODEURL":"http://sitobsb.test.citicbank.com:10001/oauthRedirect.token?TOKENIFOP=ac-2fc8994f553942ba8c33e05e16c9fcd600"}
    public AjaxResult getPayLink(String orderNo,String tranAmt,String bizType){
        Map<String,String> paramMap = new HashMap<>();;
        paramMap.put("MERNO",MERNO);
        paramMap.put("CALLBACKNOTIFYURL","https://card.zgrongyidui.com/citic/notify/payNotify.do");
        paramMap.put("CALLBACKURL","https://card.zgrongyidui.com/citic/coupons/pay-result?orderNo="+orderNo);
        paramMap.put("TRANAMT",tranAmt);
        paramMap.put("BIZTYPE",bizType);
        paramMap.put("MERORDERNO",orderNo);
        logger.info(JSON.toJSONString(paramMap));
        AjaxResult result = sendRequest("/api/citicwallet/v1/getpaylink",JSON.toJSONString(paramMap));
        return result;
    }

    //retBusiData:{"RETMSG":"交易成功！","MERJNLNO":"yJAMsQycKvFLnQCJtjsNwAntZiyXtFQi","MERNAME":"联调专用测试商户（勿动）","PAYBANKNAME":"","TRANJNLNO":"IACSPAY2023112219460311663333","TRANTIME":"","TRANAMT":"0.01","RETCODE":"AAAAAAA","STT":"01","MERORDERNO":"11111233334","SETTLEDATE":"","UNDISCOUNTAMT":"","CARDTYPE":"","DISCOUNTAMT":"","COUPONINFO":""}
    //支付查询
    public AjaxResult payResultQry(String orderNo){
        Map<String,String> paramMap = new HashMap<>();;
        paramMap.put("MERNO",MERNO);
        paramMap.put("ORDERNO",orderNo);
        logger.info(JSON.toJSONString(paramMap));
        AjaxResult result = sendRequest("/api/citicwallet/v1/payresultqry",JSON.toJSONString(paramMap));
        return result;
    }

    //退款
    public AjaxResult payRefund(String orderNo,
                                String refundNo,
                                String tranAmt,
                                String refundAmt){
        Map<String,String> paramMap = new HashMap<>();;
        paramMap.put("MERNO",MERNO);
        paramMap.put("ORDERNO",orderNo);
        paramMap.put("REFUNDNO",refundNo);
        paramMap.put("TRANAMT",tranAmt);
        paramMap.put("REFUNDAMT",refundAmt);
        logger.info(JSON.toJSONString(paramMap));
        AjaxResult result = sendRequest("/api/citicwallet/v1/payrefund",JSON.toJSONString(paramMap));
        return result;
    }

}
